"""
页面导航路径规划模型类
"""

import json
from datetime import datetime
from typing import List, Optional, Dict, Any

from pydantic import BaseModel, Field, field_validator, ConfigDict
from sqlalchemy import String, DateTime, SmallInteger, JSON, Index
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql import func

from config.database import Base


class AIWebApiCallingModel(Base):
    """页面导航路径规划数据模型 - SQLAlchemy ORM模型"""
    __tablename__ = "ai_web_api_calling"

    # SQLAlchemy字段定义
    # 主键
    page_id: Mapped[str] = mapped_column(
        String(36),
        primary_key=True,
        comment="页面的全局唯一标识符，用于唯一标识导航路径中的每个页面节点"
    )

    # 基本字段
    scene_id: Mapped[str] = mapped_column(
        String(36),
        nullable=False,
        comment="关联的业务场景唯一标识符，用于标识该导航路径所属的业务场景"
    )
    tenant_id: Mapped[str] = mapped_column(
        String(36),
        nullable=False,
        default="default",
        comment="租户ID"
    )
    page_name: Mapped[str] = mapped_column(
        String(200),
        nullable=False,
        comment="页面的中文名称，用于直观标识页面用途"
    )
    navigation_path: Mapped[str] = mapped_column(
        String(500),
        nullable=False,
        comment="页面的标准化 URL 地址，用于导航跳转，需去除 UTM 等追踪参数"
    )

    # JSON 数组字段
    page_tab: Mapped[Optional[str]] = mapped_column(
        JSON,
        nullable=True,
        comment="页面标签页，以数组形式存储页面的标签分类"
    )
    function_desc_list: Mapped[Optional[str]] = mapped_column(
        JSON,
        nullable=True,
        comment="页面功能的多维度描述，以数组形式存储不同角度的功能说明"
    )
    operation_desc_list: Mapped[Optional[str]] = mapped_column(
        JSON,
        nullable=True,
        comment="页面包含的操作集合描述，记录该页面可执行的操作及其用途"
    )
    prev_path_list: Mapped[Optional[str]] = mapped_column(
        JSON,
        nullable=True,
        comment="该页面的前置路径节点 ID 集合，记录跳转到当前页面的上一页面节点 ID"
    )
    next_path_list: Mapped[Optional[str]] = mapped_column(
        JSON,
        nullable=True,
        comment="该页面的后置路径节点 ID 集合，记录从当前页面可跳转的下一页面节点 ID"
    )
    mcp_list: Mapped[Optional[str]] = mapped_column(
        JSON,
        nullable=True,
        comment="MCP工具列表，记录与该页面相关的MCP工具列表"
    )

    # 状态字段
    is_deleted: Mapped[int] = mapped_column(
        SmallInteger,
        nullable=False,
        default=0,
        comment="删除标记：0-未删除,1-已删除"
    )

    # 审计字段
    created_by: Mapped[str] = mapped_column(
        String(50),
        nullable=False,
        comment="记录创建该导航路径规划数据的用户标识或用户名"
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime,
        nullable=False,
        default=func.current_timestamp(),
        comment="记录导航路径规划数据的创建时间"
    )
    updated_by: Mapped[Optional[str]] = mapped_column(
        String(50),
        nullable=True,
        comment="记录最后修改该导航路径规划数据的用户标识或用户名"
    )
    updated_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime,
        nullable=True,
        onupdate=func.current_timestamp(),
        comment="记录导航路径规划数据的最后修改时间"
    )

    # 索引和约束
    __table_args__ = (
        Index('idx_scene_id', 'scene_id'),
        Index('idx_tenant_id', 'tenant_id'),
        Index('idx_page_name', 'page_name'),
        Index('idx_navigation_path', 'navigation_path'),
        Index('idx_is_deleted', 'is_deleted'),
        Index('idx_created_by', 'created_by'),
        Index('idx_created_at', 'created_at'),
        Index('idx_scene_tenant_deleted', 'scene_id', 'tenant_id', 'is_deleted'),
        Index('idx_tenant_deleted_created', 'tenant_id', 'is_deleted', 'created_at'),
        {"comment": "页面导航路径规划数据表"}
    )

    def __repr__(self):
        return f"<AIWebApiCallingModel(page_id='{self.page_id}', page_name='{self.page_name}', scene_id='{self.scene_id}')>"

    def to_dict(self) -> dict:
        """转换为字典"""
        return {
            "page_id": self.page_id,
            "scene_id": self.scene_id,
            "tenant_id": self.tenant_id,
            "page_name": self.page_name,
            "page_tab": self.get_page_tab(),
            "function_desc_list": self.get_function_desc_list(),
            "operation_desc_list": self.get_operation_desc_list(),
            "navigation_path": self.navigation_path,
            "prev_path_list": self.get_prev_path_list(),
            "next_path_list": self.get_next_path_list(),
            "mcp_list": self.get_mcp_list(),
            "is_deleted": self.is_deleted,
            "created_by": self.created_by,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_by": self.updated_by,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None
        }

    def get_page_tab(self) -> List[str]:
        """获取页面标签页列表"""
        if isinstance(self.page_tab, str):
            try:
                return json.loads(self.page_tab)
            except (json.JSONDecodeError, TypeError):
                return []
        elif isinstance(self.page_tab, list):
            return self.page_tab
        return []

    def set_page_tab(self, value: List[str]):
        """设置页面标签页列表"""
        if isinstance(value, list):
            self.page_tab = json.dumps(value, ensure_ascii=False)
        else:
            self.page_tab = json.dumps([], ensure_ascii=False)

    def get_function_desc_list(self) -> List[str]:
        """获取功能描述列表"""
        if isinstance(self.function_desc_list, str):
            try:
                return json.loads(self.function_desc_list)
            except (json.JSONDecodeError, TypeError):
                return []
        elif isinstance(self.function_desc_list, list):
            return self.function_desc_list
        return []

    def set_function_desc_list(self, value: List[str]):
        """设置功能描述列表"""
        if isinstance(value, list):
            self.function_desc_list = json.dumps(value, ensure_ascii=False)
        else:
            self.function_desc_list = json.dumps([], ensure_ascii=False)

    def get_operation_desc_list(self) -> List[str]:
        """获取操作描述列表"""
        if isinstance(self.operation_desc_list, str):
            try:
                return json.loads(self.operation_desc_list)
            except (json.JSONDecodeError, TypeError):
                return []
        elif isinstance(self.operation_desc_list, list):
            return self.operation_desc_list
        return []

    def set_operation_desc_list(self, value: List[str]):
        """设置操作描述列表"""
        if isinstance(value, list):
            self.operation_desc_list = json.dumps(value, ensure_ascii=False)
        else:
            self.operation_desc_list = json.dumps([], ensure_ascii=False)

    def get_prev_path_list(self) -> List[str]:
        """获取前置路径列表"""
        if isinstance(self.prev_path_list, str):
            try:
                return json.loads(self.prev_path_list)
            except (json.JSONDecodeError, TypeError):
                return []
        elif isinstance(self.prev_path_list, list):
            return self.prev_path_list
        return []

    def set_prev_path_list(self, value: List[str]):
        """设置前置路径列表"""
        if isinstance(value, list):
            self.prev_path_list = json.dumps(value, ensure_ascii=False)
        else:
            self.prev_path_list = json.dumps([], ensure_ascii=False)

    def get_next_path_list(self) -> List[str]:
        """获取后置路径列表"""
        if isinstance(self.next_path_list, str):
            try:
                return json.loads(self.next_path_list)
            except (json.JSONDecodeError, TypeError):
                return []
        elif isinstance(self.next_path_list, list):
            return self.next_path_list
        return []

    def set_next_path_list(self, value: List[str]):
        """设置后置路径列表"""
        if isinstance(value, list):
            self.next_path_list = json.dumps(value, ensure_ascii=False)
        else:
            self.next_path_list = json.dumps([], ensure_ascii=False)

    def get_mcp_list(self) -> List[str]:
        """获取MCP工具列表"""
        if isinstance(self.mcp_list, str):
            try:
                return json.loads(self.mcp_list)
            except (json.JSONDecodeError, TypeError):
                return []
        elif isinstance(self.mcp_list, list):
            return self.mcp_list
        return []

    def set_mcp_list(self, value: List[str]):
        """设置MCP工具列表"""
        if isinstance(value, list):
            self.mcp_list = json.dumps(value, ensure_ascii=False)
        else:
            self.mcp_list = json.dumps([], ensure_ascii=False)

    @classmethod
    def from_pydantic(cls, pydantic_model: 'AIWebApiCallingSchema'):
        """从Pydantic模型创建SQLAlchemy模型实例"""
        data = pydantic_model.model_dump(
            exclude={'page_tab', 'function_desc_list', 'operation_desc_list', 'prev_path_list', 'next_path_list', 'mcp_list'})
        instance = cls(**data)

        # 处理JSON字段
        if hasattr(pydantic_model, 'page_tab') and pydantic_model.page_tab:
            instance.set_page_tab(pydantic_model.page_tab)
        if hasattr(pydantic_model, 'function_desc_list') and pydantic_model.function_desc_list:
            instance.set_function_desc_list(pydantic_model.function_desc_list)
        if hasattr(pydantic_model, 'operation_desc_list') and pydantic_model.operation_desc_list:
            instance.set_operation_desc_list(pydantic_model.operation_desc_list)
        if hasattr(pydantic_model, 'prev_path_list') and pydantic_model.prev_path_list:
            instance.set_prev_path_list(pydantic_model.prev_path_list)
        if hasattr(pydantic_model, 'next_path_list') and pydantic_model.next_path_list:
            instance.set_next_path_list(pydantic_model.next_path_list)
        if hasattr(pydantic_model, 'mcp_list') and pydantic_model.mcp_list:
            instance.set_mcp_list(pydantic_model.mcp_list)

        return instance

    def to_pydantic(self) -> 'AIWebApiCallingSchema':
        """转换为Pydantic模型"""
        return AIWebApiCallingSchema(
            page_id=self.page_id,
            scene_id=self.scene_id,
            tenant_id=self.tenant_id,
            page_name=self.page_name,
            navigation_path=self.navigation_path,
            page_tab=self.get_page_tab(),
            function_desc_list=self.get_function_desc_list(),
            operation_desc_list=self.get_operation_desc_list(),
            prev_path_list=self.get_prev_path_list(),
            next_path_list=self.get_next_path_list(),
            mcp_list=self.get_mcp_list(),
            is_deleted=self.is_deleted,
            created_by=self.created_by,
            created_at=self.created_at,
            updated_by=self.updated_by,
            updated_at=self.updated_at
        )


class AIWebApiCallingSchema(BaseModel):
    """页面导航路径规划数据模型 - Pydantic验证模型"""

    # 基本字段
    page_id: str = Field(..., max_length=36, description="页面的全局唯一标识符")
    scene_id: str = Field(..., max_length=36, description="关联的业务场景唯一标识符")
    tenant_id: str = Field(default="default", max_length=36, description="租户ID")
    page_name: str = Field(..., max_length=200, description="页面的中文名称")
    navigation_path: str = Field(..., max_length=500, description="页面的标准化 URL 地址")

    # JSON 数组字段
    page_tab: Optional[List[str]] = Field(default=None, description="页面标签页")
    function_desc_list: Optional[List[str]] = Field(default=None, description="页面功能的多维度描述")
    operation_desc_list: Optional[List[str]] = Field(default=None, description="页面包含的操作集合描述")
    prev_path_list: Optional[List[str]] = Field(default=None, description="该页面的前置路径节点 ID 集合")
    next_path_list: Optional[List[str]] = Field(default=None, description="该页面的后置路径节点 ID 集合")
    mcp_list: Optional[List[str]] = Field(default=None, description="MCP工具列表，记录与该页面相关的MCP工具列表")

    # 状态字段
    is_deleted: int = Field(default=0, description="删除标记：0-未删除,1-已删除")

    # 审计字段
    created_by: str = Field(..., max_length=50, description="创建者")
    created_at: Optional[datetime] = Field(default=None, description="创建时间")
    updated_by: Optional[str] = Field(default=None, max_length=50, description="更新者")
    updated_at: Optional[datetime] = Field(default=None, description="更新时间")

    model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True)


class AIWebApiCallingBatchCreate(BaseModel):
    """批量创建页面导航路径规划请求模型"""
    items: List[Dict[str, Any]] = Field(..., description="批量创建的页面数据列表")
    created_by: str = Field(..., max_length=50, description="创建者")

    @field_validator('items')
    @classmethod
    def validate_items(cls, v):
        """验证批量数据格式"""
        if not v:
            raise ValueError('批量创建数据不能为空')

        required_fields = ['scene_id', 'page_name', 'navigation_path']
        for i, item in enumerate(v):
            for field in required_fields:
                if field not in item or not item[field]:
                    raise ValueError(f'第{i + 1}条数据缺少必需字段：{field}')
        return v


class AIWebApiCallingBatchUpdate(BaseModel):
    """批量更新页面导航路径规划请求模型"""
    items: List[Dict[str, Any]] = Field(..., description="批量更新的页面数据列表")
    updated_by: str = Field(..., max_length=50, description="更新者")

    @field_validator('items')
    @classmethod
    def validate_items(cls, v):
        """验证批量更新数据格式"""
        if not v:
            raise ValueError('批量更新数据不能为空')

        for i, item in enumerate(v):
            if 'page_id' not in item or not item['page_id']:
                raise ValueError(f'第{i + 1}条数据缺少必需字段：page_id')
        return v


class AIWebApiCallingSearchRequest(BaseModel):
    """页面导航路径规划搜索请求模型"""
    keyword: Optional[str] = Field(None, description="搜索关键词，支持页面名称和导航路径")
    scene_ids: Optional[List[str]] = Field(None, description="场景ID列表筛选")
    function_keywords: Optional[List[str]] = Field(None, description="功能描述关键词筛选")
    operation_keywords: Optional[List[str]] = Field(None, description="操作描述关键词筛选")
    path_contains: Optional[str] = Field(None, description="路径包含关键词")
    created_date_start: Optional[datetime] = Field(None, description="创建时间开始")
    created_date_end: Optional[datetime] = Field(None, description="创建时间结束")
    page_size: int = Field(default=20, ge=1, le=100, description="分页大小")
    page_num: int = Field(default=1, ge=1, description="页码")


class AIWebApiCallingSearchResponse(BaseModel):
    """页面导航路径规划搜索响应模型"""
    total: int = Field(..., description="总数量")
    page_num: int = Field(..., description="当前页码")
    page_size: int = Field(..., description="分页大小")
    total_pages: int = Field(..., description="总页数")
    items: List[Dict[str, Any]] = Field(..., description="搜索结果列表")


class AIWebApiCallingStatistics(BaseModel):
    """页面导航路径规划统计模型"""
    total_pages: int = Field(..., description="总页面数")
    total_scenes: int = Field(..., description="涉及场景数")
    avg_function_count: float = Field(..., description="平均功能描述数量")
    avg_operation_count: float = Field(..., description="平均操作描述数量")
    most_common_functions: List[Dict[str, Any]] = Field(..., description="最常见的功能描述")
    most_common_operations: List[Dict[str, Any]] = Field(..., description="最常见的操作描述")
    scene_page_distribution: List[Dict[str, Any]] = Field(..., description="场景页面分布")


class AIWebApiCallingExport(BaseModel):
    """页面导航路径规划导出模型"""
    scene_ids: Optional[List[str]] = Field(None, description="要导出的场景ID列表")
    export_format: str = Field(default="json", description="导出格式：json, csv, excel")
    include_deleted: bool = Field(default=False, description="是否包含已删除数据")

    @field_validator('export_format')
    @classmethod
    def validate_export_format(cls, v):
        """验证导出格式"""
        if v not in ['json', 'csv', 'excel']:
            raise ValueError('导出格式只能是 json, csv, excel 中的一个')
        return v


class AIWebApiCallingImport(BaseModel):
    """页面导航路径规划导入模型"""
    data: List[Dict[str, Any]] = Field(..., description="导入的数据列表")
    import_mode: str = Field(default="insert",
                             description="导入模式：insert-仅插入, update-更新已存在, upsert-插入或更新")
    created_by: str = Field(..., max_length=50, description="导入者")

    @field_validator('import_mode')
    @classmethod
    def validate_import_mode(cls, v):
        """验证导入模式"""
        if v not in ['insert', 'update', 'upsert']:
            raise ValueError('导入模式只能是 insert, update, upsert 中的一个')
        return v

    @field_validator('data')
    @classmethod
    def validate_data(cls, v):
        """验证导入数据格式"""
        if not v:
            raise ValueError('导入数据不能为空')

        required_fields = ['scene_id', 'page_name', 'navigation_path']
        for i, item in enumerate(v):
            for field in required_fields:
                if field not in item or not item[field]:
                    raise ValueError(f'第{i + 1}条数据缺少必需字段：{field}')
        return v


class AIWebApiCallingPathAnalysis(BaseModel):
    """页面路径分析模型"""
    page_id: str = Field(..., description="页面ID")
    depth: int = Field(..., description="路径深度")
    incoming_count: int = Field(..., description="入链数量")
    outgoing_count: int = Field(..., description="出链数量")
    is_entry_point: bool = Field(..., description="是否为入口页面")
    is_exit_point: bool = Field(..., description="是否为出口页面")
    path_score: float = Field(..., description="路径重要度分数")


class AIWebApiCallingPathGraph(BaseModel):
    """页面路径图谱模型"""
    nodes: List[Dict[str, Any]] = Field(..., description="节点列表")
    edges: List[Dict[str, Any]] = Field(..., description="边列表")
    graph_metrics: Dict[str, Any] = Field(..., description="图谱指标")


class AIWebApiCallingValidationResult(BaseModel):
    """页面导航路径规划验证结果模型"""
    is_valid: bool = Field(..., description="是否验证通过")
    errors: List[str] = Field(default_factory=list, description="错误信息列表")
    warnings: List[str] = Field(default_factory=list, description="警告信息列表")
    suggestions: List[str] = Field(default_factory=list, description="建议信息列表")


class AIWebApiCallingDuplicateCheck(BaseModel):
    """页面导航路径规划重复检查模型"""
    check_fields: List[str] = Field(default_factory=lambda: ["navigation_path"], description="检查重复的字段")
    scene_id: Optional[str] = Field(None, description="在特定场景内检查重复")
    ignore_deleted: bool = Field(default=True, description="是否忽略已删除的记录")


class AIWebApiCallingDuplicateResult(BaseModel):
    """页面导航路径规划重复检查结果模型"""
    has_duplicates: bool = Field(..., description="是否存在重复")
    duplicate_groups: List[List[Dict[str, Any]]] = Field(..., description="重复数据分组")
    total_duplicates: int = Field(..., description="重复记录总数")


class AIWebApiCallingBackup(BaseModel):
    """页面导航路径规划备份模型"""
    backup_id: str = Field(..., description="备份ID")
    backup_name: str = Field(..., description="备份名称")
    backup_description: Optional[str] = Field(None, description="备份描述")
    scene_ids: Optional[List[str]] = Field(None, description="备份的场景ID列表")
    created_by: str = Field(..., max_length=50, description="备份创建者")
    created_at: datetime = Field(..., description="备份创建时间")
    data_count: int = Field(..., description="备份的数据条数")
    file_size: int = Field(..., description="备份文件大小（字节）")


class AIWebApiCallingRestore(BaseModel):
    """页面导航路径规划恢复模型"""
    backup_id: str = Field(..., description="要恢复的备份ID")
    restore_mode: str = Field(default="replace", description="恢复模式：replace-替换, merge-合并")
    target_scene_ids: Optional[List[str]] = Field(None, description="目标场景ID列表")
    restored_by: str = Field(..., max_length=50, description="恢复操作者")

    @field_validator('restore_mode')
    @classmethod
    def validate_restore_mode(cls, v):
        """验证恢复模式"""
        if v not in ['replace', 'merge']:
            raise ValueError('恢复模式只能是 replace 或 merge')
        return v
